💡 本筆記內容源自溫宏斌老師的物件導向程式設計OCW。
* | & | |
---|---|---|
宣告 | 指標 | 別名呼叫 |
使用 | 解參考 | 取出位址(Address of Operator) |
(一)基本定義
指標是程式的重要概念,指涉的可以是變數、指標和函數的位址。
1.指涉變數位址的例子
int *ptr1
//任意資料型態(先不定義內容)的變數
void *ptr2
//如ch.2-1自定義的變數
AirTicket *ptr3
float x = 2;
//指標pt中存放一個float變數的位址
float *pt;
//&會把x的記憶體位置抓出來,再assign到左邊的pt去,此時x的記憶體位置就會寫入pt裡面
pt = &x;
2.指涉指標位址的例子,如下例的變數c
float a = 1, *b, **c;
b = &a
c = &b
3.指涉函數位址的例子
由於每個function block在code section都有自己記憶體位置,就可以找指標指向這個位置
int fc1 (char x, char y);
//function pointer
int (*fp) (char a, int b);
fp = fc1;
fp = fc1("x",5); //錯誤,因為fc1應該要返回int,而非function pointer
:bulb:注意:function pointer會加上(),避免誤會成回傳是pointer!
4.指涉array中元素位址的例子
比index快
array indexing | pointer notation | |
---|---|---|
第0位 | array[0] | *array |
第1位 | array[1] | *(array+1) |
※補充:什麼是code section?
記憶體中儲存可執行程式碼的區域。
下圖是一張說明multithreaded的圖,在多線運行時,最上排的code section、data section和os資源(如檔案)是共享的。
圖片來源:周志遠教授作業系統 Chap3 Processes Concept講義
(二)為什麼要使用指標
1.可以進行動態分配,避免浪費空間。
2.透過指標化直接修改實際參數(如果只是做call by value,改不到原來的參數。)
※ 補充:C++ 的求值策略(Evaluation strategy)-Call by Value, Call by Reference
call by value | call by reference | |
---|---|---|
內容 | 參數引用的方式,單純是個數值,跟原本的變數毫無關聯 | 引用變數而非數值 |
例子 | void add(int a, int b) | void add(int *a, int *b) |
舉例而言,由於call by reference是直接引用變數,所以呼叫函式以後,原本變數的值就會改變,如下例變數a所指涉到的位置中的值由6改為12。
void add(int *a, int *b) {
*a = *a + *b;
}
int main() {
int a = 6;
int b = 6;
add(&a, &b);
print("a = %d", a); // 這邊印出的是 a = 12
return 0;
}
(一)定義
參考被稱為淺型的pointer,它可以自動解參考(不需要*),也就是可以自動取出被指到的值。
三種使用方式:
1.被視為獨立變數
💡因為是幫別人取別名,參考對象和別名變數的資料形態要一致,在初始化就要宣告好!
double num = 0.07
double &refnum = num
2.作為參數傳遞給函數
以前面提過call by reference例子來說,語法更直觀,不需要操作記憶體位址。
//add.cpp
void add(int &a, int &b) {
a = a + b;
}
//main() in main.cpp
int main() {
int a = 6;
int b = 6;
add(a, b);
cout << "a = " << a << endl; // a = 12
return 0;
}
3.由函式返回作為結果
//回傳的和傳入的東西用的是同一塊記憶體
int& fun(int *a, int i){
//return a[i]這個變數(而非該變數的值)
if (i>0 && i<5) return a[i];
else exit(0);
}
//iary:整數array
for (int idx=0; idx<5; idx++)
//假設收到a[3] 會執行 a[3] = 3*2
fun(iary,idx) = idx*2
💡如果是int fun(int * a, int i),就會錯誤,因為return的是int(a[i]的值),非a[i]。
避免函式無預警地改掉內容值,有時我們會使用constant,可分為四種類型:
int x = 5;
const int& xref = x;
x = 33; //原變數可以改變
cout << xref; //33
xref = 15; //前面已宣告別名變數只能讀不能改
int x = 5, y = 6;
const int *pt = &x;
cout << *pt; //5
pt =&y;
cout << *pt; //7
*pt = 11; //錯誤,pt存取的記憶體位指可變,但位指解參考的內容不可變。
int var1 = 3, var2 = 5;
int * const cpt = &var1;
*cpt = 8; //8
cpt = &var2//錯誤,
const int v1 = 11, v2 = 22;
const int *cptc = &v1;
*cptc = 33 //錯誤
cout << *cptc; //11
cptc = & v2;
cout << *cptc; //22
(一)基本操作
不同於C常用malloc()和free()來操作動態記憶體分配,C++使用new和delete,範例如下:
//宣告一個指標dpt,並用new分配空間給他
double *dpt = new double(0,0);
if (dpt == NULL)
{
cout << "insuffcient memory.\n";
exit(1);
}
*dpt = 3.4;
//將空間還給heap
delete dpt;
值得注意的是,針對compile前已經宣告的變數,也就是使用stack記憶體的變數,如果只單純delete p不會真正消滅stack裡的p,而是歸還*p指到的位址。
int *p = new int(5);
delete pl
動態分配記憶體時,要注意有無歸還空間,避免浪費記憶體。
(二)如何創立動態Array
在資料結構課程中,一般的Array是a set of index and value,且大小是一開始就宣告好的。不過缺點是可能浪費記憶體空間。
於是,就有了dynamic arrays
int iSize = 0;
cin >> iSize;
typedef double* DoublePtr;
DoublePtr d;
//創設dynamic arrays
d = new double[iSize];
...
//歸還空間
delete []d;
//表示沒有指到任何真實空間
d = NULL;
Q1.python是Call by Value,還是 Call by Reference?
A1:Python 是Pass by Assignment。
引數傳的是物件的參照(Call by Object Reference),但此處的Reference 是由 Pass by Value 的方式實作。
※參考文章:
Python 是 Pass By Value, Pass by Reference, 還是 Pass by Sharing?
Python官方文件
怎麼定義類別